////////////////////////////////////////////////////////////////////////////// 
//
//  gen_sync.v
//
//  Generic clock domain crossing synchronizer.  Simply stages a signal
//  through three flops to protect against metastability.  Requires that
//  sampling clock is faster than source clock.
//
//  Original Author: 
//  Current Owner:   
//
////////////////////////////////////////////////////////////////////////////// 
//
// Copyright (C) 2012 Synopsys, Inc.  All rights reserved.
//
// SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of
// Synopsys, Inc., and is fully protected under copyright and trade secret
// laws.  You may not view, use, disclose, copy, or distribute this file or
// any information contained herein except pursuant to a valid written
// license agreement. It may not be used, reproduced, or disclosed to others
// except in accordance with the terms and conditions of that agreement.
//
////////////////////////////////////////////////////////////////////////////// 
//
//    Perforce Information
//    $Author:  
//    $File:  /rtl/gen_sync.v $
//    $DateTime:  
//    $Revision:  
//
////////////////////////////////////////////////////////////////////////////// 

module np_gen_sync 
  #(parameter RST_LOW = 0,
    parameter RST_VAL = 0,
    parameter MAX_CHK_EN = 0, // Use setup window checking for metastability modelling.
    parameter ASYNC = 1,
    parameter SETUP = 900,
    parameter QRND = 1,
    parameter QVAL = 0, 
    parameter META_RISE = 1,
    parameter META_FALL = 1) (
output wire q,
input  wire rst,
input  wire clk,
input  wire d
);

// Create a version of the input which is synchronized with the local clock
//
// %%SYNTH:
//   set_false_path -from $nonscan_clks -to $inst/d_s1_reg/next_state
//   set_false_path -from $scan_clks -through $inst/d_s1_reg/next_state -to $nonscan_clks
//

// 
// RST_LOW = 0 => active high reset input
// RST_LOW = 1 => active low  reset input
wire   rst_int = (RST_LOW == 1) ? !rst : rst;

`ifdef ANI_SIM_MODE
  // Create a shadow register that always samples new data on the clock (never goes metastable)
  reg shadow;
  always @ (posedge clk or posedge rst_int)
	if (rst_int)
      shadow <= RST_VAL;
	else
      shadow <= d;

wire d_in_dly;
assign #(SETUP*0.001) d_in_dly = d;
`endif

reg d_s1; 
reg d_s2;
reg d_s3;

always @ (posedge clk or posedge rst_int) begin
  if (rst_int) begin
	d_s1 <= RST_VAL;
	d_s2 <= RST_VAL;
	d_s3 <= RST_VAL;
  end 
  else begin
`ifdef ANI_SIM_MODE  // ifdef simulation mode only (not synth)
  if (MAX_CHK_EN) begin
    if (ASYNC == 0) begin
      d_s1 <= d;
    end
    // Cause a timing violation on the d_s1 flop if the 
    // d input does not meet the SETUP requirement.
    // d_s1 is either randomized or set to QVAL based on RAND   
    else if (d_in_dly != d) begin
      if (QRND == 1)
        d_s1 <= `ANI_RANDOM;
      else
        d_s1 <= QVAL;
    end
    else begin
      d_s1 <= d;
    end
  end // (MAX_CHK_EN)
  else begin // Pessimistic metastability modelling.
    if (((META_RISE==1) & (META_FALL==1)) || 
        ((META_RISE==1) & (META_FALL==0) & d==1) || 
        ((META_RISE==0) & (META_FALL==1) & d==0)
       ) begin
      if (d != shadow) begin                  // if input changed since the last time we had a clock
		d_s1 <= `ANI_RANDOM;            // randomize the first flop
      end
      else 
        d_s1 <= d;
    end
    else begin
      d_s1 <= d;
    end
  end // Pessimistic metastability modelling.
`else                                        
    d_s1 <= d;  // Synthesis path 
`endif
    d_s2 <= d_s1;
    d_s3 <= d_s2;
  end
end
    
assign q = d_s3;
    
endmodule
